/*
 * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "sle_host_proxy.h"
#include "sle_hilog.h"

namespace OHOS {
namespace NearLink {
namespace SleStandard {
int32_t SleHostProxy::InnerTransact(
    uint32_t code, MessageOption &flags, MessageParcel &data, MessageParcel &reply)
{
    auto remote = Remote();
    if (remote == nullptr) {
        SLE_LOGE("[InnerTransact] fail: get Remote fail code %{public}d", code);
        return OBJECT_NULL;
    }
    int32_t err = remote->SendRequest(code, data, reply, flags);
    if (err != NO_ERROR) {
        SLE_LOGE("[InnerTransact] fail: ipcErr=%{public}d code %{public}d", err, code);
    }
    return err;
}

SleErrorCode SleHostProxy::RegisterHostCallback(const sptr<ISleHostCallback> &callback)
{
    SLE_LOGD("RegisterHostCallback In");
    MessageParcel data;
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteInterfaceToken(SleHostProxy::GetDescriptor()), SLE_ERR_IPC_TRANS_FAILED, "write interface token failed!");
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteRemoteObject(callback->AsObject()), SLE_ERR_IPC_TRANS_FAILED, "write host callback failed!");

    MessageParcel reply;
    MessageOption option = {MessageOption::TF_SYNC};
    int32_t result = InnerTransact(SleHostInterfaceCode::SLE_REGISTER_HOST_CALLBACK, option, data, reply);
    if (result != NO_ERROR) {
        SLE_LOGE("transact done fail, error code: %{public}d", result);
        return SLE_ERR_IPC_TRANS_FAILED;
    }
    int32_t ret = reply.ReadInt32();
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "register host callback failed(%{public}d)", ret);
    return (SleErrorCode)ret;
}

SleErrorCode SleHostProxy::UnregisterHostCallback(const sptr<ISleHostCallback> &callback)
{
    SLE_LOGD("UnregisterHostCallback In");
    MessageParcel data;
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteInterfaceToken(SleHostProxy::GetDescriptor()), SLE_ERR_IPC_TRANS_FAILED, "write interface token failed!");
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteRemoteObject(callback->AsObject()), SLE_ERR_IPC_TRANS_FAILED, "write host callback failed!");

    MessageParcel reply;
    MessageOption option = {MessageOption::TF_SYNC};
    int32_t result = InnerTransact(SleHostInterfaceCode::SLE_UNREGISTER_HOST_CALLBACK, option, data, reply);
    if (result != NO_ERROR) {
        SLE_LOGE("transact done fail, error code: %{public}d", result);
        return SLE_ERR_IPC_TRANS_FAILED;
    }
    int32_t ret = reply.ReadInt32();
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "unregister host callback failed(%{public}d)", ret);
    return (SleErrorCode)ret;
}

SleErrorCode SleHostProxy::EnableSle()
{
    MessageParcel data;
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteInterfaceToken(SleHostProxy::GetDescriptor()), SLE_ERR_IPC_TRANS_FAILED, "write interface token failed!");

    MessageParcel reply;
    MessageOption option = {MessageOption::TF_SYNC};
    int32_t result = InnerTransact(SleHostInterfaceCode::SLE_ENABLE, option, data, reply);
    if (result != NO_ERROR) {
        SLE_LOGE("transact done fail, error code: %{public}d", result);
        return SLE_ERR_IPC_TRANS_FAILED;
    }
    int32_t ret = reply.ReadInt32();
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "enable sle failed(%{public}d)", ret);
    return (SleErrorCode)ret;
}

SleErrorCode SleHostProxy::DisableSle()
{
    MessageParcel data;
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteInterfaceToken(SleHostProxy::GetDescriptor()), SLE_ERR_IPC_TRANS_FAILED, "write interface token failed!");

    MessageParcel reply;
    MessageOption option = {MessageOption::TF_SYNC};
    int32_t result = InnerTransact(SleHostInterfaceCode::SLE_DISABLE, option, data, reply);
    if (result != NO_ERROR) {
        SLE_LOGE("transact done fail, error code: %{public}d", result);
        return SLE_ERR_IPC_TRANS_FAILED;
    }
    int32_t ret = reply.ReadInt32();
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "disable sle failed(%{public}d)", ret);
    return (SleErrorCode)ret;
}

SleErrorCode SleHostProxy::GetSleState(int32_t &state)
{
    MessageParcel data;
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteInterfaceToken(SleHostProxy::GetDescriptor()), SLE_ERR_IPC_TRANS_FAILED, "write interface token failed!");

    MessageParcel reply;
    MessageOption option = {MessageOption::TF_SYNC};
    int32_t result = InnerTransact(SleHostInterfaceCode::SLE_GET_SLE_STATE, option, data, reply);
    if (result != NO_ERROR) {
        SLE_LOGE("transact done fail, error code: %{public}d", result);
        return SLE_ERR_IPC_TRANS_FAILED;
    }
    int32_t exception = reply.ReadInt32();
    SLE_ASSERT_AND_RETURN_RET_LOG(exception == NO_ERROR, exception, "get sle state failed!(%d)", exception);
    state = reply.ReadInt32();
    return (SleErrorCode)exception;
}

SleErrorCode SleHostProxy::GetHostAddress(SleAddress &address)
{
    MessageParcel data;
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteInterfaceToken(SleHostProxy::GetDescriptor()), SLE_ERR_IPC_TRANS_FAILED, "write interface token failed!");

    MessageParcel reply;
    MessageOption option = {MessageOption::TF_SYNC};
    int32_t result = InnerTransact(SleHostInterfaceCode::SLE_GET_HOST_ADDRESS, option, data, reply);
    if (result != NO_ERROR) {
        SLE_LOGE("transact done fail, error code: %{public}d", result);
        return SLE_ERR_IPC_TRANS_FAILED;
    }
    int32_t exception = reply.ReadInt32();
    SLE_ASSERT_AND_RETURN_RET_LOG(exception == NO_ERROR, exception, "get host address failed!(%d)", exception);
    std::unique_ptr<SleAddress> addr(reply.ReadParcelable<SleAddress>());
    SLE_ASSERT_AND_RETURN_RET_LOG(addr, SLE_ERR_IPC_TRANS_FAILED, "address null failed!");
    address = *addr;
    return (SleErrorCode)exception;
}

SleErrorCode SleHostProxy::SetHostName(const std::string name)
{
    MessageParcel data;
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteInterfaceToken(SleHostProxy::GetDescriptor()), SLE_ERR_IPC_TRANS_FAILED, "write interface token failed!");
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteString(name), SLE_ERR_IPC_TRANS_FAILED, "write host name failed!");

    MessageParcel reply;
    MessageOption option = {MessageOption::TF_SYNC};
    int32_t result = InnerTransact(SleHostInterfaceCode::SLE_SET_HOST_NAME, option, data, reply);
    if (result != NO_ERROR) {
        SLE_LOGE("transact done fail, error code: %{public}d", result);
        return SLE_ERR_IPC_TRANS_FAILED;
    }
    SleErrorCode ret = (SleErrorCode)reply.ReadInt32();
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "set host name failed(%{public}d)", ret);
    return ret;
}

SleErrorCode SleHostProxy::GetHostName(std::string &name)
{
    MessageParcel data;
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteInterfaceToken(SleHostProxy::GetDescriptor()), SLE_ERR_IPC_TRANS_FAILED, "write interface token failed!");

    MessageParcel reply;
    MessageOption option = {MessageOption::TF_SYNC};
    int32_t result = InnerTransact(SleHostInterfaceCode::SLE_GET_HOST_NAME, option, data, reply);
    if (result != NO_ERROR) {
        SLE_LOGE("transact done fail, error code: %{public}d", result);
        return SLE_ERR_IPC_TRANS_FAILED;
    }
    int32_t exception = reply.ReadInt32();
    SLE_ASSERT_AND_RETURN_RET_LOG(exception == NO_ERROR, exception, "get host name failed!(%d)", exception);
    name = reply.ReadString(); 
    return (SleErrorCode)exception;
}

SleErrorCode SleHostProxy::GetHostDefaultConnectConfig(SleConnectConfig &hostConnParam)
{
    MessageParcel data;
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteInterfaceToken(SleHostProxy::GetDescriptor()), SLE_ERR_IPC_TRANS_FAILED, "write interface token failed!");

    MessageParcel reply;
    MessageOption option = {MessageOption::TF_SYNC};
    int32_t result = InnerTransact(SleHostInterfaceCode::SLE_GET_DEFAULT_CONN_CONFIG, option, data, reply);
    if (result != NO_ERROR) {
        SLE_LOGE("transact done fail, error code: %{public}d", result);
        return SLE_ERR_IPC_TRANS_FAILED;
    }
    int32_t exception = reply.ReadInt32();
    SLE_ASSERT_AND_RETURN_RET_LOG(exception == NO_ERROR, exception, "get host connectConfig failed!(%d)", exception);
    hostConnParam.connectInterval = reply.ReadUint16(); 
    hostConnParam.connectTimeout = reply.ReadUint16(); 
    hostConnParam.connectLatency = reply.ReadUint16(); 
    hostConnParam.mtuSize = reply.ReadUint32(); 
    hostConnParam.mcs = reply.ReadUint8(); 
    hostConnParam.pilotDensity = reply.ReadUint8(); 
    hostConnParam.formatType = reply.ReadUint8(); 
    hostConnParam.dataLen = reply.ReadUint16(); 
    hostConnParam.phy = reply.ReadUint8(); 
    return (SleErrorCode)exception;
}

SleErrorCode SleHostProxy::StartFlowMonitor()
{
    MessageParcel data;
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteInterfaceToken(SleHostProxy::GetDescriptor()), SLE_ERR_IPC_TRANS_FAILED, "write interface token failed!");
    MessageParcel reply;
    MessageOption option = {MessageOption::TF_SYNC};
    int32_t result = InnerTransact(SleHostInterfaceCode::SLE_START_FLOW_MONITOR, option, data, reply);
    if (result != NO_ERROR) {
        SLE_LOGE("transact done fail, error code: %{public}d", result);
        return SLE_ERR_IPC_TRANS_FAILED;
    }
    SleErrorCode ret = (SleErrorCode)reply.ReadInt32();
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "start flow monitor failed(%{public}d)", ret);
    return ret;
}

SleErrorCode SleHostProxy::StopFlowMonitor()
{
    MessageParcel data;
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteInterfaceToken(SleHostProxy::GetDescriptor()), SLE_ERR_IPC_TRANS_FAILED, "write interface token failed!");
    MessageParcel reply;
    MessageOption option = {MessageOption::TF_SYNC};
    int32_t result = InnerTransact(SleHostInterfaceCode::SLE_STOP_FLOW_MONITOR, option, data, reply);
    if (result != NO_ERROR) {
        SLE_LOGE("transact done fail, error code: %{public}d", result);
        return SLE_ERR_IPC_TRANS_FAILED;
    }
    SleErrorCode ret = (SleErrorCode)reply.ReadInt32();
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "stop flow monitor failed(%{public}d)", ret);
    return ret;
}

sptr<IRemoteObject> SleHostProxy::GetSleServerRemote(const std::string &name)
{
    MessageParcel data;
    if (!data.WriteInterfaceToken(SleHostProxy::GetDescriptor())) {
        SLE_LOGE("write interface token failed!");
        return nullptr;
    }
    if (!data.WriteString(name)) {
        SLE_LOGE("write server name failed!");
        return nullptr;
    }
    MessageParcel reply;
    MessageOption option = {MessageOption::TF_SYNC};
    int32_t result = InnerTransact(SleHostInterfaceCode::SLE_GET_SLE_SERVER_REMOTE, option, data, reply);
    if (result != NO_ERROR) {
        SLE_LOGE("transact done fail, error code: %{public}d", result);
        return nullptr;
    }
    return reply.ReadStrongParcelable<IRemoteObject>();
}
} // SleStandard
} // NearLink
} // OHOS